/*******************************************************************************
 * Copyright (c) 2008 Sylvain Sicard.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Lesser Public License v2.1
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * 
 * Contributors:
 *     Sylvain Sicard - initial API and implementation
 ******************************************************************************/
package fr.jade.service.fm.reactor;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.objectweb.fractal.api.Component;
import org.objectweb.fractal.api.NoSuchInterfaceException;
import org.objectweb.fractal.api.control.BindingController;
import org.objectweb.fractal.api.control.IllegalBindingException;
import org.objectweb.fractal.api.control.IllegalLifeCycleException;

import fr.jade.base.JadeBaseComponent;
import fr.jade.event.Event;
import fr.jade.event.EventBody;
import fr.jade.event.EventHandler;
import fr.jade.reflex.util.Reflex;
import fr.jade.service.fm.deployment.Deployer;
import fr.jade.service.fm.deployment.DeploymentTask;
import fr.jade.service.fm.deployment.NewComponentTask;
import fr.jade.service.nodes.allocator.Allocator;
import fr.jade.service.nodes.allocator.AllocatorException;
import fr.jade.util.JadeException;

public class ReactorImpl extends JadeBaseComponent implements EventHandler, BindingController {


  // BINDINGS
  protected final static String cleanerItfName = "cleaner";
  protected Cleaner cleaner = null;
  
  protected final static String deployerItfName = "deployer";
  protected Deployer deployer = null;
  
  protected final static String analyserItfName = "analyser";
  protected Analyser analyser = null;
  
  protected final static String policyItfName = "policy";
  protected Policy policy = null;
  
  protected final static String allocatorItfName = "allocator";
  protected Allocator allocator = null;
	
  protected final static String plannerItfName = "planner";
  protected Planner planner = null;

  protected static final String[] itfList = new String[]{allocatorItfName, deployerItfName, analyserItfName, policyItfName, cleanerItfName, plannerItfName};
  
	// Impl of EventHandler interface
	public void handleEvent(Event e) throws JadeException{
		EventBody eb = e.getEventBody();
		Component failedNode_M = (Component)eb.get("failedCmp_M");
		synchronized (this) {
		  Map<Component, NewComponentTask> context = new HashMap<Component, NewComponentTask>();
			try {
        
  			Component newNode_E = allocator.alloc(null);
  			Component newNode_M = Reflex.getDualComponent(newNode_E);
  			
  			Set<Component> failedCmp_M = analyser.analyseFailedComponents(failedNode_M);
  			Set<Component> impactedCmp_M = analyser.analyseImpactedComponents(failedCmp_M);
  			if(impactedCmp_M.contains(failedNode_M)) impactedCmp_M.remove(failedNode_M);
  			Set<DeploymentTask> recoveryTasks = policy.execute(context, failedCmp_M, impactedCmp_M, newNode_M);
  			
  			cleaner.execute(failedCmp_M, impactedCmp_M, failedNode_M);
  			
  			List<DeploymentTask> recoveryPlan = planner.createPlan(recoveryTasks);
  			
  			deployer.deploy(recoveryPlan);
  			
  		} catch (AllocatorException e1) {
        throw new JadeException("Cannot alloc a new node", e1);
      }
		}

	}

	// implem of binding controller
	public String[] listFc() {
		return super.concat(itfList, super.listFc());
	}

	public Object lookupFc(final String itfName) throws NoSuchInterfaceException {
	  if (itfName.equals(cleanerItfName)) {
      return cleaner;
    } else if (itfName.equals(policyItfName)) {
      return policy;
    } else if (itfName.equals(analyserItfName)) {
      return analyser;
    } else if (itfName.equals(allocatorItfName)) {
			return allocator;
		} else if (itfName.equals(deployerItfName)) {
      return deployer;
    } else if (itfName.equals(plannerItfName)) {
      return planner;
    } else {
      return super.lookupFc(itfName);
    }
	}

	public void bindFc(final String itfName, final Object itfValue) throws NoSuchInterfaceException, IllegalBindingException, IllegalLifeCycleException {
	  if (itfName.equals(cleanerItfName)) {
      cleaner = (Cleaner) itfValue;
    } else if (itfName.equals(policyItfName)) {
      policy = (Policy) itfValue;
    } else if (itfName.equals(analyserItfName)) {
      analyser = (Analyser) itfValue;
    } else if (itfName.equals(deployerItfName)) {
      deployer = (Deployer) itfValue;
    } else if (itfName.equals(allocatorItfName)) {
			allocator = (Allocator) itfValue;
		} else if (itfName.equals(plannerItfName)) {
      planner = (Planner) itfValue;
    } else {
      super.bindFc(itfName, itfValue);
    }
	}

	public void unbindFc(final String itfName) throws NoSuchInterfaceException, IllegalBindingException, IllegalLifeCycleException {
	  if (itfName.equals(cleanerItfName)) {
      cleaner = null;
    } else if (itfName.equals(policyItfName)) {
      policy = null;
    } else if (itfName.equals(analyserItfName)) {
      analyser = null;
    } else if (itfName.equals(deployerItfName)) {
      deployer = null;
    } else if (itfName.equals(allocatorItfName)) {
			allocator = null;
		} else if (itfName.equals(plannerItfName)) {
      planner = null;
    } else {
      super.unbindFc(itfName);
    }
	}

}

